﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using ICSharpCode.SharpZipLib.Checksums;
using ICSharpCode.SharpZipLib.Zip;

namespace SharpZipDemo
{
    static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }

        /// <summary>
        /// 解压缩文件
        /// </summary>
        /// <param name="zipfilepath">待解压缩的文件路径</param>
        /// <param name="unzippath">解压缩到指定目录</param>
        public static void UnZip(string zipfilepath, string unzippath)
        {
            ZipInputStream zipInputStream = new ZipInputStream(File.OpenRead(zipfilepath));
            ZipEntry theEntry;
            while ((theEntry = zipInputStream.GetNextEntry()) != null)
            {
                string directoryName = Path.GetDirectoryName(unzippath);
                string fileName = Path.GetFileName(theEntry.Name);
                //生成解压目录
                Directory.CreateDirectory(directoryName);
                if (fileName != String.Empty)
                {
                    //如果文件的压缩后大小为0那么说明这个文件是空的,因此不需要进行读出写入
                    if (theEntry.CompressedSize == 0)
                        break;
                    //解压文件到指定的目录
                    directoryName = Path.GetDirectoryName(unzippath + theEntry.Name);
                    //建立下面的目录和子目录
                    Directory.CreateDirectory(directoryName);
                    FileStream streamWriter = File.Create(unzippath + theEntry.Name);
                    int size = 2048;
                    byte[] data = new byte[2048];
                    while (true)
                    {
                        size = zipInputStream.Read(data, 0, data.Length);
                        if (size > 0)
                        {
                            streamWriter.Write(data, 0, size);
                        }
                        else
                        {
                            break;
                        }
                    }
                    streamWriter.Close();
                }
            }
            zipInputStream.Close();
        }

        /// <summary>
        /// 压缩文件
        /// 指定目录或者指定文件
        /// </summary>
        /// <param name="filespath">要压缩的文件路径</param>
        /// <param name="zipfilename">压缩后文件保存路径</param>
        /// <param name="fileFilter">对指定的文件进行压缩</param>
        /// <returns>bool</returns>
        public static bool ZipFile(string filespath, string zipfilename, string fileFilter)
        {
            try
            {
                //如果文件没有找到则报错。
                if (!File.Exists(filespath))
                {
                    throw new FileNotFoundException("指定的文件路径 " + filespath + " 无法找到该文件");
                }

                Crc32 crc32 = new Crc32();
                ZipOutputStream zipOutputStream = new ZipOutputStream(File.Create(zipfilename));
                zipOutputStream.SetLevel(6); // 设置压缩率 0~9 
                DirectoryInfo directoryInfo = new DirectoryInfo(filespath);
                FileInfo[] fileInfos = directoryInfo.GetFiles(fileFilter);
                cutStr = filespath.Trim();
                //压缩这个目录下的所有文件
                writeStream(ref zipOutputStream, fileInfos, crc32);
                //压缩这个目录下子目录及其文件
                direct(directoryInfo, ref zipOutputStream, crc32);

                zipOutputStream.Finish();
                zipOutputStream.Close();
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.ToString());
                return false;
            }
            return true;
        }

        private static string cutStr = "";
        //获取所有的目录信息
        private static void direct(DirectoryInfo di, ref ZipOutputStream s, Crc32 crc)
        {
            DirectoryInfo[] dirs = di.GetDirectories("*");
            //遍历目录下面的所有的子目录
            foreach (DirectoryInfo dirNext in dirs)
            {
                //将该目录下的所有文件添加到 ZipOutputStream s 压缩流里面
                FileInfo[] a = dirNext.GetFiles();
                writeStream(ref s, a, crc);
                //递归调用直到把所有的目录遍历完成
                direct(dirNext, ref s, crc);
            }
        }

        private static void writeStream(ref ZipOutputStream s, FileInfo[] a, Crc32 crc)
        {
            foreach (FileInfo fi in a)
            {
                FileStream fs = fi.OpenRead();
                byte[] buffer = new byte[fs.Length];
                fs.Read(buffer, 0, buffer.Length);

                string file = fi.FullName;
                file = file.Replace(cutStr, "");

                ZipEntry entry = new ZipEntry(file);
                entry.DateTime = DateTime.Now;

                //设置大小和CRC，因为信息
                //关于大小和CRC应存放在头
                //如果没有设置，它会自动写入在页脚。
                //在这种情况下，大小== CRC在头== -1）
                //一些zip程序zip文件，不存储问题
                //在头的大小和CRC。
                entry.Size = fs.Length;
                fs.Close();

                crc.Reset();
                crc.Update(buffer);
                entry.Crc = crc.Value;
                s.PutNextEntry(entry);
                s.Write(buffer, 0, buffer.Length);
            }
        }
    }
}
